로딩 중이에요... 🐣
[코담]
웹개발·실전 프로젝트·AI까지, 파이썬·장고의 모든것을 담아낸 강의와 개발 노트
19 데이터 충돌 및 중복 처리 | ✅ 저자: 이유정(박사)
데이터 중복이 왜 문제인가요?
-
“하나만 있어야 할 정보”가 여러 번 나타나면
- 예를 들어 주문 번호나 회원 아이디처럼 고유해야 할 값이 중복되면, 실제로는 하나의 주문이나 한 명의 회원인 것을 두 번 이상 셈하게 됩니다.
- 이렇게 되면 “총 몇 건의 주문이 들어왔나요?” 같은 간단한 집계 결과도 실제보다 크게 나와서, 잘못된 의사결정을 내릴 수 있습니다.
-
사용자 정보에 오류(중복)가 있으면 활동이 과장될 수 있습니다
- 같은 사람이 가입만 여러 번 했다고 보면, “활동 유저 수”나 “구매 고객 수”가 실제보다 많아집니다.
- 예를 들어 고객 A가 실제로 1번만 구매했는데, 데이터가 중복되어 A가 3명처럼 보이면 “3번 구매한 고객이 있다”는 식으로 잘못 해석될 수 있습니다.
쉽게 생각해 보기
-
도서관 책 대출 기록을 관리하는데, 같은 책이 두 번 대출된 기록이 남아 있다면 “책을 두 번 대출했나?” 하고 헷갈리는 것과 같습니다.
-
운동 기록 앱에서 A 사용자가 한 번만 달리기를 했는데, 기록이 중복 저장돼 A가 두 번 달리기를 한 것처럼 보이면, 통계가 틀어집니다.
결국 원본 데이터의 고유성(unique) 이 깨지면, 그 데이터를 바탕으로 하는 모든 분석·보고·의사결정이 잘못될 위험이 커집니다.
import pandas as pd
# CSV 파일 불러오기
df = pd.read_csv("csv_files/combined_customers.csv")
# 처음 10줄 미리 보기
print("-----처음 10줄 미리 보기--------")
print(df.head(10))
# 중복된 customer_id 찾기 (첫 번째 항목을 남기고 나머지를 중복으로 판단)
duplicates = df.duplicated(subset='customer_id', keep='first')
# 중복된 행 출력 (== 제거될 행들)
removed_rows = df[duplicates]
print("\n-----제거될 행들-----")
print(removed_rows)
# 중복 제거
df_cleaned = df.drop_duplicates(subset='customer_id', keep='first')
# 결과 출력
print("\n-----중복 제거 후 데이터 수-----")
print(f"원래 데이터 수: {len(df)}")
print(f"중복 제거 후 데이터 수: {len(df_cleaned)}")
# 중복 제거 후 미리 보기
print("\n-----중복 제거된 데이터 미리 보기 (상위 10줄)-----")
print(df_cleaned.head(10))
pandas
에서 중복된 데이터를 찾기 위한 핵심 코드
duplicates = df.duplicated(subset='customer_id', keep='first')
df.duplicated(...)
pandas
의duplicated()
함수는
데이터프레임에서 중복된 행을 찾을 때 사용하는 함수입니다.- 이 함수는 각 줄(행)이 중복인지 아닌지를 판단해서 True/False로 알려줘요.
subset='customer_id'
- 중복을 판단할 때 어떤 컬럼(열)을 기준으로 할지 정하는 거예요
- 고객 정보가 담긴 표에서
customer_id
를 기준으로 같은 ID가 여러 번 나오는지 확인합니다.
keep='first'
- 중복된 값들 중에서 첫 번째는 남기고(True안줌) 나머지는 중복(True)로 표시하라는 뜻입니다. 상황예시:
index customer_id name
0 1 Eunice
1 2 Bob
3 3 Aice
4 1 Eunice
5 2 Bob
결과:
0 False # customer_id=1 → 첫 번째니까 중복 아님
1 False # customer_id=2 → 첫 번째니까 중복 아님
2 False # customer_id=1 → 첫 번째니까 중복 아님
3 True # customer_id=3 → 두 번째 나왔으니 중복
4 True # customer_id=2 → 두 번째 나왔으니 중복
실습 문제: 중복된 고객 데이터 처리하기 목표:
- 고객 ID가 같은 행들 중에서 이메일이 서로 다른 경우를 식별합니다.
- 이처럼 ID는 같은데 이메일이 다른 경우는 데이터 충돌로 간주하고 따로 추출해야 합니다.
- 또한 ID와 이메일이 둘 다 같은 경우는 진짜 중복이므로 제거합니다.
[문제 배경]
고객 데이터 병합 중에 customer_id
가 같은데, 이메일 정보가 서로 다른 경우가 발견되었습니다.
이는 고객 ID 중복으로 인해 발생한 데이터 충돌 사례입니다.
반면, ID와 이메일이 모두 같으면 단순 중복일 수 있으므로, 그건 제거 대상입니다.
업무 요청사항:
- 고객 ID 기준으로 이메일이 서로 다른 경우를 찾아서 따로 분리합니다.
- 나머지 데이터 중에서, ID와 이메일이 모두 같은 경우는 1개만 남기고 중복 제거합니다.
- 충돌 데이터 수와 일반 중복 제거 후 데이터 수를 출력합니다.
- 충돌 데이터는 따로
conflict_df
, 정제된 데이터는cleaned_df
로 저장하여 출력합니다.
해야 할 작업 순서
combined_customers.csv
파일을 읽어서df
로 저장합니다.customer_id
별로 이메일이 서로 다른 행이 있는 경우만 따로 뽑아conflict_df
로 저장합니다.- 위에서 뽑힌 충돌 데이터를 제외한 나머지에서 ID+이메일 기준으로 중복 제거합니다.
conflict_df
,cleaned_df
각각의 크기와 상위 5행을 출력합니다.
정답코드
import pandas as pd
# 1. 데이터 불러오기
df = pd.read_csv("csv_files/combined_customers.csv")
# 2. 이메일 충돌 확인: 같은 ID인데 이메일이 다른 경우
email_counts = df.groupby('customer_id')['email'].nunique()
conflict_ids = email_counts[email_counts > 1].index
# 3. 충돌 데이터만 따로 추출
conflict_df = df[df['customer_id'].isin(conflict_ids)]
# 4. 충돌 데이터 제외
df_remaining = df[~df['customer_id'].isin(conflict_ids)]
# ~는 Pandas에서 "not", 즉 부정(반대)을 의미하는 논리 연산자입니다.
# ~는 이 결과를 반대로 뒤집는 연산자입니다.
# 5. 남은 데이터에서 ID + 이메일 기준으로 중복 제거
cleaned_df = df_remaining.drop_duplicates(subset=['customer_id', 'email'], keep='first')
# 6. 결과 출력
print(f"충돌 고객 수: {conflict_df['customer_id'].nunique()}명")
print(f"정제된 고객 수: {cleaned_df['customer_id'].nunique()}명")
print("\n충돌된 데이터 일부:")
print(conflict_df.head())
print("\n정제된 데이터 일부:")
print(cleaned_df.head())